package com.lqapi.util;

import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.elasticsearch.client.RequestOptions.DEFAULT;

//es 工具类
@Component
public class ElasticsearchUtile {
    @Qualifier("restHighLevelClient")
    @Autowired
    private RestHighLevelClient client;


    /**
     * 创建索引
     *
     * @param indexName 索引名
     * @return
     */
    public boolean createIndex(String indexName) {
        //创建索引的请求
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        //客户端执行请求IndicesClient
        CreateIndexResponse response = null;
        try {
            response = client.indices().create(request, DEFAULT);
        } catch (IOException e) {
            System.out.println("创建出错了...错误:" + e.getMessage());
        }
        //   System.out.println( response.isAcknowledged());
        return response.isAcknowledged();
    }


    /**
     * 删除索引
     *
     * @param indexName 索引名
     * @return
     */
    public boolean deleteIndex(String indexName) {
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        AcknowledgedResponse response = null;
        try {
            response = client.indices().delete(request, DEFAULT);
        } catch (IOException e) {
            System.out.println("创建出错了...错误:" + e.getMessage());
        }
        return response.isAcknowledged();
    }

    /**
     * 判断索引是否存在
     *
     * @doesTheIndexExist IOException
     */
    public boolean doesTheIndexExist(String nameIndex) {
        GetIndexRequest request = new GetIndexRequest(nameIndex);
        boolean exists = false;
        try {
            exists = client.indices().exists(request, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return exists;
    }


    /**
     * 创建文档
     * 规则 put /kuang_index/_doc/1
     *
     * @param indexName 索引
     * @param obj       存储的对象
     * @return
     */
    public boolean addDocuments(String indexName, Object obj, Object id) {
        //创建请求
        IndexRequest request = new IndexRequest(indexName);

        //规则 put /kuang_index/_doc/1
        request.id(String.valueOf(id));
        request.timeout(TimeValue.timeValueDays(1));
        request.timeout("1s");

        //将我们的数据放入请求 json
        request.source(JSON.toJSONString(obj), XContentType.JSON);

        //客户端发送请求
        IndexResponse response = null;
        try {
            response = client.index(request, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
 /*       System.out.println(response.toString());
        System.out.println(response.status()); //返回我们的状态*/
        return response.status().equals("CREATED");
    }

    /**
     * 创建文档   规则 put /kuang_index/_doc/1
     *
     * @param indexName 索引名
     * @param obj       存储的数据
     * @param id        唯一id
     * @param Millis    超时分钟
     * @return
     */
    public boolean addDocuments(String indexName, Object obj, Object id, String Millis) {
        //创建请求
        IndexRequest request = new IndexRequest(indexName);

        //规则 put /kuang_index/_doc/1
        request.id(String.valueOf(id));
        request.timeout(TimeValue.timeValueMillis(1));

        //将我们的数据放入请求 json
        request.source(JSON.toJSONString(obj), XContentType.JSON);

        //客户端发送请求
        IndexResponse response = null;
        try {
            response = client.index(request, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
 /*       System.out.println(response.toString());
        System.out.println(response.status()); //返回我们的状态*/
        return response.status().equals("CREATED");
    }


    /**
     * 判断当前文档是个存在
     *
     * @param indexName 索引名
     * @param id        唯一id
     * @return
     */
    public boolean doesTheDocumentExist(String indexName, Object id) {
        GetRequest getRequest = new GetRequest(indexName, String.valueOf(id));
        //不回去返回的——source的上下文了
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        boolean flag = false;
        try {
            flag = client.exists(getRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return flag;
    }


    /**
     * 获取文档信息
     *
     * @param indexName 索引名
     * @param id        唯一id
     * @return
     */
    public Object getDocumentation(String indexName, Object id) {
        GetRequest getRequest = new GetRequest(indexName, String.valueOf(id));
        GetResponse response = null;
        try {
            response = client.get(getRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String string = response.getSourceAsString();
        return string;
    }

    /**
     * 增强版  获取文档信息
     *
     * @param indexName 索引名
     * @param id        唯一id
     * @param clAss     实体类的class
     * @return
     */
    public Object getDocumentation(String indexName, Object id, Class clAss) {
        GetRequest getRequest = new GetRequest(indexName, String.valueOf(id));
        GetResponse response = null;
        try {
            response = client.get(getRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String string = response.getSourceAsString();
        return JSON.parseObject(string, clAss);
    }


    /**
     * 修改文档
     *
     * @param indexName 创建索引名
     * @param obj       更新后的数据
     * @param id        id
     * @return
     */
    public boolean modifyTheDocument(String indexName, Object obj, Object id) {
        UpdateRequest request = new UpdateRequest(indexName, String.valueOf(id));
        request.timeout("1s");
        request.doc(JSON.toJSONString(obj), XContentType.JSON);
        UpdateResponse response = null;
        try {
            response = client.update(request, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.status().toString().hashCode() == "OK".hashCode();
    }

    /**
     * 删除文档
     *
     * @param indexName 创建索引
     * @param id        id
     * @return
     */
    public boolean deleteDocument(String indexName, Object id) {
        DeleteRequest request = new DeleteRequest(indexName, String.valueOf(id));
        request.timeout("1s");
        DeleteResponse delete = null;
        try {
            delete = client.delete(request, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return delete.status().toString().hashCode() == "OK".hashCode();
    }


    /**
     * 数据的批量插入     //特殊的 真的项目一般都会批量插入数据
     *
     * @param indexName 创建索引名
     * @param list      数据集
     * @param Millis    超时时长
     */
    public boolean bulkInsertData(String indexName, List list, long Millis) {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(TimeValue.timeValueMillis(Millis));


        //批处理请求
        for (int i = 0; i < list.size(); i++) {
            //批量更新和批量删除 就在这里修改对应的请求就可以了
            bulkRequest.add(
                    new IndexRequest(indexName)
                            .id("" + (i + 1)
                            ).source(JSON.toJSONString(list.get(i)), XContentType.JSON));
        }
        BulkResponse bulk = null;
        try {
            bulk = client.bulk(bulkRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return !bulk.hasFailures();
    }

    /**
     * 条件查询
     *
     * @param indexName 索引名
     * @param map       条件构造
     * @param startPage 从那一页开始
     * @param endPage   结束页
     * @return
     */
    public List includeQuery(String indexName, Map<String, Object> map, Integer startPage, Integer endPage, Class dataClass) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        // 构建搜索
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //查询条件 我们可以使用QueryBuilders 工具来 实现
        //QueryBuilders.termQuery  精确查找
        //QueryBuilders.matchAllQuery 匹配所有
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            TermQueryBuilder termQuery = QueryBuilders.termQuery(entry.getKey(), entry.getValue());
            sourceBuilder.query(termQuery);
        }

        sourceBuilder.from(startPage); //从第几个开始显示
        sourceBuilder.size(endPage);///显示的多少
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);
        SearchResponse response = null;
        try {
            response = client.search(searchRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //解析结果
        ArrayList<Object> list = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            String sourceAsString = hit.getSourceAsString();//原来的结果
            list.add(JSON.parseObject(sourceAsString, dataClass));
        }
        return list;
    }


    /**
     * * 查询
     * * searchRequest 搜索请求
     * * SearchSourceBuilder 条件构造
     * * HighlightBuilder 构造高亮
     * * TermQueryBuilder 精确查询
     * * xxx QueryBuilder
     *
     * @param indexName    索引名
     * @param map          查询条件
     * @param numericField 高亮字段
     * @param startPage    第几个开始
     * @param endPage      个数
     * @param startTag     开头标签
     * @param endTag       结束标签
     */
    public List highlightConditionQuery(String indexName, Map<String, Object> map,
                                        List<String> numericField, Integer startPage,
                                        Integer endPage, String startTag, String endTag
            , Class dataClass) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        // 构建搜索
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询条件 我们可以使用QueryBuilders 工具来 实现
        //QueryBuilders.termQuery  精确查找
        //QueryBuilders.matchAllQuery 匹配所有
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            TermQueryBuilder termQuery = QueryBuilders.termQuery(entry.getKey(), entry.getValue());
            sourceBuilder.query(termQuery);
        }

        //高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        //设置高亮字段
        for (String fieIdName : numericField) {
            highlightBuilder.field(fieIdName);
        }
        //如果要多个字段高亮,这项要为false
        highlightBuilder.requireFieldMatch(true);
        highlightBuilder.preTags(startTag);
        highlightBuilder.postTags(endTag);
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段
        sourceBuilder.highlighter(highlightBuilder);
        sourceBuilder.from(startPage); //从第几个开始显示
        sourceBuilder.size(endPage);///显示的多少
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        searchRequest.source(sourceBuilder);

        SearchResponse response = null;
        try {
            response = client.search(searchRequest, DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //  System.out.println(response.getHits());
        //  System.out.println("*******************************************");
        //解析结果
        ArrayList<Object> list = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            //解析高亮的字段
            //获取高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            //System.out.println("==name==" + content);
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            //将原来的字段替换为高亮字段即可
            for (String fieIdName : numericField) {
                HighlightField content = highlightFields.get(fieIdName);
                if (content != null) {
                    Text[] fragments = content.fragments();
                    String newTitle = "";
                    for (Text text : fragments) {
                        newTitle += text;
                    }
                    sourceAsMap.put(fieIdName, newTitle);//替换掉原来的内容
                }
            }
            list.add(sourceAsMap.toString());
        }
        String data = JSON.toJSONString(list);
        ArrayList list1 = JSON.parseObject(data, new ArrayList<>().getClass());
        return list1;
    }

}
